using System.Net;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Text.Json;

namespace JGSY.CMS.LowCode.Platform.Middleware
{
    /// <summary>
    /// 全局异常处理中间件
    /// 用于捕获和处理应用程序中未处理的异常，提供统一的错误响应格式
    /// </summary>
    public class GlobalExceptionMiddleware
    {
        /// <summary>
        /// 下一个中间件委托
        /// </summary>
        private readonly RequestDelegate _next;
        
        /// <summary>
        /// 日志记录器
        /// </summary>
        private readonly ILogger<GlobalExceptionMiddleware> _logger;

        /// <summary>
        /// 初始化全局异常处理中间件的新实例
        /// </summary>
        /// <param name="next">下一个中间件委托</param>
        /// <param name="logger">日志记录器实例</param>
        public GlobalExceptionMiddleware(RequestDelegate next, ILogger<GlobalExceptionMiddleware> logger)
        {
            _next = next;
            _logger = logger;
        }

        /// <summary>
        /// 异步调用中间件处理HTTP请求
        /// 捕获处理过程中的异常并进行统一处理
        /// </summary>
        /// <param name="context">HTTP上下文</param>
        /// <returns>异步任务</returns>
        public async Task InvokeAsync(HttpContext context)
        {
            try
            {
                await _next(context);
            }
            catch (Exception ex)
            {
                var traceId = Activity.Current?.TraceId.ToString() ?? context.TraceIdentifier;
                _logger.LogError(ex, "[GlobalException] TraceId:{TraceId} Path:{Path} Message:{Message}", traceId, context.Request.Path, ex.Message);
                await HandleExceptionAsync(context, ex, traceId);
            }
        }

        /// <summary>
        /// 处理异常并返回统一格式的错误响应
        /// </summary>
        /// <param name="context">HTTP上下文</param>
        /// <param name="exception">捕获的异常</param>
        /// <param name="traceId">请求跟踪标识符</param>
        /// <returns>异步任务</returns>
        private static async Task HandleExceptionAsync(HttpContext context, Exception exception, string traceId)
        {
            context.Response.ContentType = "application/json";
            context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            var result = JsonSerializer.Serialize(new
            {
                code = 500,
                message = "服务器内部错误，请联系管理员。",
                traceId,
                details = exception.Message
            });
            await context.Response.WriteAsync(result);
        }
    }
}
